mobbdev 0.0.84 → 0.0.86

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.mjs +491 -112
  2. package/package.json +2 -1
package/dist/index.mjs CHANGED
@@ -173,7 +173,6 @@ var CliError = class extends Error {
173
173
  };
174
174
 
175
175
  // src/features/analysis/index.ts
176
- import { Octokit as Octokit3 } from "@octokit/core";
177
176
  import chalk4 from "chalk";
178
177
  import Configstore from "configstore";
179
178
  import Debug10 from "debug";
@@ -476,6 +475,17 @@ var GET_FIX = gql2`
476
475
  }
477
476
  }
478
477
  `;
478
+ var GET_FIXES = gql2`
479
+ query getFixes($filters: fix_bool_exp!) {
480
+ fixes: fix(where: $filters) {
481
+ issueType
482
+ id
483
+ patchAndQuestions {
484
+ patch
485
+ }
486
+ }
487
+ }
488
+ `;
479
489
  var GET_VUL_BY_NODES_METADATA = gql2`
480
490
  query getVulByNodesMetadata(
481
491
  $filters: [vulnerability_report_issue_code_node_bool_exp!]
@@ -486,6 +496,7 @@ var GET_VUL_BY_NODES_METADATA = gql2`
486
496
  where: {
487
497
  _or: $filters
488
498
  vulnerabilityReportIssue: {
499
+ fixId: { _is_null: false }
489
500
  vulnerabilityReportId: { _eq: $vulnerabilityReportId }
490
501
  }
491
502
  }
@@ -498,6 +509,35 @@ var GET_VUL_BY_NODES_METADATA = gql2`
498
509
  fixId
499
510
  }
500
511
  }
512
+ fixablePrVuls: vulnerability_report_issue_aggregate(
513
+ where: {
514
+ fixId: { _is_null: false }
515
+ vulnerabilityReportId: { _eq: $vulnerabilityReportId }
516
+ codeNodes: { _or: $filters }
517
+ }
518
+ ) {
519
+ aggregate {
520
+ count
521
+ }
522
+ }
523
+ nonFixablePrVuls: vulnerability_report_issue_aggregate(
524
+ where: {
525
+ fixId: { _is_null: true }
526
+ vulnerabilityReportId: { _eq: $vulnerabilityReportId }
527
+ codeNodes: { _or: $filters }
528
+ }
529
+ ) {
530
+ aggregate {
531
+ count
532
+ }
533
+ }
534
+ totalScanVulnerabilities: vulnerability_report_issue_aggregate(
535
+ where: { vulnerabilityReportId: { _eq: $vulnerabilityReportId } }
536
+ ) {
537
+ aggregate {
538
+ count
539
+ }
540
+ }
501
541
  }
502
542
  `;
503
543
 
@@ -711,15 +751,17 @@ var GetAnalysisQueryZ = z2.object({
711
751
  })
712
752
  })
713
753
  });
714
- var GetFixQueryZ = z2.object({
715
- fix_by_pk: z2.object({
716
- issueType: z2.string(),
717
- id: z2.string(),
718
- patchAndQuestions: z2.object({
719
- patch: z2.string()
720
- })
754
+ var FixDataZ = z2.object({
755
+ issueType: z2.string(),
756
+ id: z2.string(),
757
+ patchAndQuestions: z2.object({
758
+ patch: z2.string()
721
759
  })
722
760
  });
761
+ var GetFixQueryZ = z2.object({
762
+ fix_by_pk: FixDataZ
763
+ });
764
+ var GetFixesQueryZ = z2.object({ fixes: z2.array(FixDataZ) });
723
765
  var VulnerabilityReportIssueCodeNodeZ = z2.object({
724
766
  vulnerabilityReportIssueId: z2.string(),
725
767
  path: z2.string(),
@@ -729,7 +771,22 @@ var VulnerabilityReportIssueCodeNodeZ = z2.object({
729
771
  })
730
772
  });
731
773
  var GetVulByNodesMetadataZ = z2.object({
732
- vulnerabilityReportIssueCodeNodes: z2.array(VulnerabilityReportIssueCodeNodeZ)
774
+ vulnerabilityReportIssueCodeNodes: z2.array(VulnerabilityReportIssueCodeNodeZ),
775
+ nonFixablePrVuls: z2.object({
776
+ aggregate: z2.object({
777
+ count: z2.number()
778
+ })
779
+ }),
780
+ fixablePrVuls: z2.object({
781
+ aggregate: z2.object({
782
+ count: z2.number()
783
+ })
784
+ }),
785
+ totalScanVulnerabilities: z2.object({
786
+ aggregate: z2.object({
787
+ count: z2.number()
788
+ })
789
+ })
733
790
  });
734
791
 
735
792
  // src/features/analysis/graphql/gql.ts
@@ -844,7 +901,6 @@ var GQLClient = class {
844
901
  const filters = hunks.map((hunk) => {
845
902
  const filter = {
846
903
  path: { _eq: hunk.path },
847
- vulnerabilityReportIssue: { fixId: { _is_null: false } },
848
904
  _or: hunk.ranges.map(({ endLine, startLine }) => ({
849
905
  startLine: { _gte: startLine, _lte: endLine },
850
906
  endLine: { _gte: startLine, _lte: endLine }
@@ -868,10 +924,20 @@ var GQLClient = class {
868
924
  [vulnerabilityReportIssueCodeNode.vulnerabilityReportIssueId]: vulnerabilityReportIssueCodeNode
869
925
  };
870
926
  }, {});
927
+ const nonFixablePrVuls = parsedGetVulByNodesMetadataRes.nonFixablePrVuls.aggregate.count;
928
+ const fixablePrVuls = parsedGetVulByNodesMetadataRes.fixablePrVuls.aggregate.count;
929
+ const totalScanVulnerabilities = parsedGetVulByNodesMetadataRes.totalScanVulnerabilities.aggregate.count;
930
+ const vulnerabilitiesOutsidePr = totalScanVulnerabilities - nonFixablePrVuls - fixablePrVuls;
931
+ const totalPrVulnerabilities = nonFixablePrVuls + fixablePrVuls;
871
932
  return {
872
933
  vulnerabilityReportIssueCodeNodes: Object.values(
873
934
  uniqueVulByNodesMetadata
874
- )
935
+ ),
936
+ nonFixablePrVuls,
937
+ fixablePrVuls,
938
+ totalScanVulnerabilities,
939
+ vulnerabilitiesOutsidePr,
940
+ totalPrVulnerabilities
875
941
  };
876
942
  }
877
943
  async digestVulnerabilityReport({
@@ -977,9 +1043,19 @@ var GQLClient = class {
977
1043
  );
978
1044
  return GetFixQueryZ.parse(res);
979
1045
  }
1046
+ async getFixes(fixIds) {
1047
+ const res = await this._client.request(
1048
+ GET_FIXES,
1049
+ {
1050
+ filters: { id: { _in: fixIds } }
1051
+ }
1052
+ );
1053
+ return GetFixesQueryZ.parse(res);
1054
+ }
980
1055
  };
981
1056
 
982
1057
  // src/features/analysis/handle_finished_analysis.ts
1058
+ import { Octokit as Octokit3 } from "@octokit/core";
983
1059
  import Debug4 from "debug";
984
1060
  import parseDiff from "parse-diff";
985
1061
  import { z as z9 } from "zod";
@@ -1009,7 +1085,7 @@ import { Octokit } from "octokit";
1009
1085
  import { z as z3 } from "zod";
1010
1086
 
1011
1087
  // src/features/analysis/scm/urlParser.ts
1012
- function getRepoInfo(pathname, hostname) {
1088
+ function getRepoInfo(pathname, hostname, scmType) {
1013
1089
  const hostnameParts = hostname.split(".");
1014
1090
  if (hostnameParts.length === 3 && hostnameParts[1] === "visualstudio" && hostnameParts[2] === "com") {
1015
1091
  if (pathname.length === 2 && pathname[0] === "_git") {
@@ -1027,7 +1103,7 @@ function getRepoInfo(pathname, hostname) {
1027
1103
  };
1028
1104
  }
1029
1105
  }
1030
- if (hostname === "dev.azure.com") {
1106
+ if (hostname === "dev.azure.com" || scmType === "Ado" /* Ado */) {
1031
1107
  if (pathname.length === 3 && pathname[1] === "_git") {
1032
1108
  return {
1033
1109
  organization: pathname[0],
@@ -1043,7 +1119,7 @@ function getRepoInfo(pathname, hostname) {
1043
1119
  };
1044
1120
  }
1045
1121
  }
1046
- if (hostname === "github.com") {
1122
+ if (hostname === "github.com" || scmType === "GitHub" /* GitHub */) {
1047
1123
  if (pathname.length === 2) {
1048
1124
  return {
1049
1125
  organization: pathname[0],
@@ -1052,7 +1128,7 @@ function getRepoInfo(pathname, hostname) {
1052
1128
  };
1053
1129
  }
1054
1130
  }
1055
- if (hostname === "gitlab.com") {
1131
+ if (hostname === "gitlab.com" || scmType === "GitLab" /* GitLab */) {
1056
1132
  if (pathname.length >= 2) {
1057
1133
  return {
1058
1134
  organization: pathname[0],
@@ -1064,12 +1140,12 @@ function getRepoInfo(pathname, hostname) {
1064
1140
  return null;
1065
1141
  }
1066
1142
  var NAME_REGEX = /[a-z0-9\-_.+]+/i;
1067
- var parseScmURL = (scmURL) => {
1143
+ var parseScmURL = (scmURL, scmType) => {
1068
1144
  try {
1069
1145
  const url = new URL(scmURL);
1070
1146
  const hostname = url.hostname.toLowerCase();
1071
1147
  const projectPath = url.pathname.substring(1).replace(/.git$/i, "");
1072
- const repo = getRepoInfo(projectPath.split("/"), hostname);
1148
+ const repo = getRepoInfo(projectPath.split("/"), hostname, scmType);
1073
1149
  if (!repo)
1074
1150
  return null;
1075
1151
  const { organization, repoName, projectName } = repo;
@@ -1089,6 +1165,22 @@ var parseScmURL = (scmURL) => {
1089
1165
  return null;
1090
1166
  }
1091
1167
  };
1168
+ var sanityRepoURL = (scmURL) => {
1169
+ try {
1170
+ const url = new URL(scmURL);
1171
+ const projectPath = url.pathname.substring(1).replace(/.git$/i, "");
1172
+ const pathParts = projectPath.split("/");
1173
+ if (pathParts.length < 2)
1174
+ return false;
1175
+ if (pathParts.length > 4)
1176
+ return false;
1177
+ if (pathParts.some((part) => !part.match(NAME_REGEX)))
1178
+ return false;
1179
+ return true;
1180
+ } catch (e) {
1181
+ return null;
1182
+ }
1183
+ };
1092
1184
 
1093
1185
  // src/features/analysis/scm/github/github.ts
1094
1186
  function removeTrailingSlash(str) {
@@ -1369,7 +1461,7 @@ async function getCommit({
1369
1461
  }
1370
1462
  function parseGithubOwnerAndRepo(gitHubUrl) {
1371
1463
  gitHubUrl = removeTrailingSlash(gitHubUrl);
1372
- const parsingResult = parseScmURL(gitHubUrl);
1464
+ const parsingResult = parseScmURL(gitHubUrl, "GitHub" /* GitHub */);
1373
1465
  if (!parsingResult || parsingResult.hostname !== "github.com") {
1374
1466
  throw new InvalidUrlPatternError(`invalid github repo Url ${gitHubUrl}`);
1375
1467
  }
@@ -1527,6 +1619,9 @@ var UPDATE_COMMENT_PATH = "PATCH /repos/{owner}/{repo}/pulls/comments/{comment_i
1527
1619
  var GET_PR_COMMENTS_PATH = "GET /repos/{owner}/{repo}/pulls/{pull_number}/comments";
1528
1620
  var GET_PR_COMMENT_PATH = "GET /repos/{owner}/{repo}/pulls/comments/{comment_id}";
1529
1621
  var GET_PR = "GET /repos/{owner}/{repo}/pulls/{pull_number}";
1622
+ var POST_GENERAL_PR_COMMENT = "POST /repos/{owner}/{repo}/issues/{issue_number}/comments";
1623
+ var GET_GENERAL_PR_COMMENTS = "GET /repos/{owner}/{repo}/issues/{issue_number}/comments";
1624
+ var DELETE_GENERAL_PR_COMMENT = "DELETE /repos/{owner}/{repo}/issues/comments/{comment_id}";
1530
1625
  var CREATE_OR_UPDATE_A_REPOSITORY_SECRET = "PUT /repos/{owner}/{repo}/actions/secrets/{secret_name}";
1531
1626
  var GET_A_REPOSITORY_PUBLIC_KEY = "GET /repos/{owner}/{repo}/actions/secrets/public-key";
1532
1627
 
@@ -1558,10 +1653,20 @@ function createOrUpdateRepositorySecret(client, params) {
1558
1653
  function getARepositoryPublicKey(client, params) {
1559
1654
  return client.request(GET_A_REPOSITORY_PUBLIC_KEY, params);
1560
1655
  }
1656
+ function postGeneralPrComment(client, params) {
1657
+ return client.request(POST_GENERAL_PR_COMMENT, params);
1658
+ }
1659
+ function getGeneralPrComments(client, params) {
1660
+ return client.request(GET_GENERAL_PR_COMMENTS, params);
1661
+ }
1662
+ function deleteGeneralPrComment(client, params) {
1663
+ return client.request(DELETE_GENERAL_PR_COMMENT, params);
1664
+ }
1561
1665
 
1562
1666
  // src/features/analysis/scm/gitlab.ts
1563
1667
  import querystring from "node:querystring";
1564
1668
  import { Gitlab } from "@gitbeaker/rest";
1669
+ import { ProxyAgent } from "undici";
1565
1670
  import { z as z4 } from "zod";
1566
1671
  function removeTrailingSlash2(str) {
1567
1672
  return str.trim().replace(/\/+$/, "");
@@ -1572,17 +1677,19 @@ var EnvVariablesZod2 = z4.object({
1572
1677
  var { GITLAB_API_TOKEN } = EnvVariablesZod2.parse(process.env);
1573
1678
  function getGitBeaker(options) {
1574
1679
  const token = options?.gitlabAuthToken ?? GITLAB_API_TOKEN ?? "";
1680
+ const url = options.url;
1681
+ const host = url ? new URL(url).origin : "https://gitlab.com";
1575
1682
  if (token?.startsWith("glpat-") || token === "") {
1576
- return new Gitlab({ token });
1683
+ return new Gitlab({ token, host });
1577
1684
  }
1578
- return new Gitlab({ oauthToken: token });
1685
+ return new Gitlab({ oauthToken: token, host });
1579
1686
  }
1580
1687
  async function gitlabValidateParams({
1581
1688
  url,
1582
1689
  accessToken
1583
1690
  }) {
1584
1691
  try {
1585
- const api2 = getGitBeaker({ gitlabAuthToken: accessToken });
1692
+ const api2 = getGitBeaker({ url, gitlabAuthToken: accessToken });
1586
1693
  if (accessToken) {
1587
1694
  await api2.Users.showCurrentUser();
1588
1695
  }
@@ -1603,8 +1710,8 @@ async function gitlabValidateParams({
1603
1710
  throw e;
1604
1711
  }
1605
1712
  }
1606
- async function getGitlabUsername(accessToken) {
1607
- const api2 = getGitBeaker({ gitlabAuthToken: accessToken });
1713
+ async function getGitlabUsername(url, accessToken) {
1714
+ const api2 = getGitBeaker({ url, gitlabAuthToken: accessToken });
1608
1715
  const res = await api2.Users.showCurrentUser();
1609
1716
  return res.username;
1610
1717
  }
@@ -1615,7 +1722,7 @@ async function getGitlabIsUserCollaborator({
1615
1722
  }) {
1616
1723
  try {
1617
1724
  const { projectPath } = parseGitlabOwnerAndRepo(repoUrl);
1618
- const api2 = getGitBeaker({ gitlabAuthToken: accessToken });
1725
+ const api2 = getGitBeaker({ url: repoUrl, gitlabAuthToken: accessToken });
1619
1726
  const res = await api2.Projects.show(projectPath);
1620
1727
  const members = await api2.ProjectMembers.all(res.id, {
1621
1728
  includeInherited: true
@@ -1631,7 +1738,7 @@ async function getGitlabMergeRequestStatus({
1631
1738
  mrNumber
1632
1739
  }) {
1633
1740
  const { projectPath } = parseGitlabOwnerAndRepo(repoUrl);
1634
- const api2 = getGitBeaker({ gitlabAuthToken: accessToken });
1741
+ const api2 = getGitBeaker({ url: repoUrl, gitlabAuthToken: accessToken });
1635
1742
  const res = await api2.MergeRequests.show(projectPath, mrNumber);
1636
1743
  switch (res.state) {
1637
1744
  case "merged" /* merged */:
@@ -1648,7 +1755,7 @@ async function getGitlabIsRemoteBranch({
1648
1755
  branch
1649
1756
  }) {
1650
1757
  const { projectPath } = parseGitlabOwnerAndRepo(repoUrl);
1651
- const api2 = getGitBeaker({ gitlabAuthToken: accessToken });
1758
+ const api2 = getGitBeaker({ url: repoUrl, gitlabAuthToken: accessToken });
1652
1759
  try {
1653
1760
  const res = await api2.Branches.show(projectPath, branch);
1654
1761
  return res.name === branch;
@@ -1656,8 +1763,8 @@ async function getGitlabIsRemoteBranch({
1656
1763
  return false;
1657
1764
  }
1658
1765
  }
1659
- async function getGitlabRepoList(accessToken) {
1660
- const api2 = getGitBeaker({ gitlabAuthToken: accessToken });
1766
+ async function getGitlabRepoList(url, accessToken) {
1767
+ const api2 = getGitBeaker({ url, gitlabAuthToken: accessToken });
1661
1768
  const res = await api2.Projects.all({
1662
1769
  membership: true,
1663
1770
  //TODO: a bug in the sorting mechanism of this api call
@@ -1690,7 +1797,7 @@ async function getGitlabBranchList({
1690
1797
  repoUrl
1691
1798
  }) {
1692
1799
  const { projectPath } = parseGitlabOwnerAndRepo(repoUrl);
1693
- const api2 = getGitBeaker({ gitlabAuthToken: accessToken });
1800
+ const api2 = getGitBeaker({ url: repoUrl, gitlabAuthToken: accessToken });
1694
1801
  try {
1695
1802
  const res = await api2.Branches.all(projectPath, {
1696
1803
  perPage: 100,
@@ -1705,7 +1812,10 @@ async function getGitlabBranchList({
1705
1812
  }
1706
1813
  async function createMergeRequest(options) {
1707
1814
  const { projectPath } = parseGitlabOwnerAndRepo(options.repoUrl);
1708
- const api2 = getGitBeaker({ gitlabAuthToken: options.accessToken });
1815
+ const api2 = getGitBeaker({
1816
+ url: options.repoUrl,
1817
+ gitlabAuthToken: options.accessToken
1818
+ });
1709
1819
  const res = await api2.MergeRequests.create(
1710
1820
  projectPath,
1711
1821
  options.sourceBranchName,
@@ -1718,7 +1828,10 @@ async function createMergeRequest(options) {
1718
1828
  return res.iid;
1719
1829
  }
1720
1830
  async function getGitlabRepoDefaultBranch(repoUrl, options) {
1721
- const api2 = getGitBeaker({ gitlabAuthToken: options?.gitlabAuthToken });
1831
+ const api2 = getGitBeaker({
1832
+ url: repoUrl,
1833
+ gitlabAuthToken: options?.gitlabAuthToken
1834
+ });
1722
1835
  const { projectPath } = parseGitlabOwnerAndRepo(repoUrl);
1723
1836
  const project = await api2.Projects.show(projectPath);
1724
1837
  if (!project.default_branch) {
@@ -1728,7 +1841,10 @@ async function getGitlabRepoDefaultBranch(repoUrl, options) {
1728
1841
  }
1729
1842
  async function getGitlabReferenceData({ ref, gitlabUrl }, options) {
1730
1843
  const { projectPath } = parseGitlabOwnerAndRepo(gitlabUrl);
1731
- const api2 = getGitBeaker({ gitlabAuthToken: options?.gitlabAuthToken });
1844
+ const api2 = getGitBeaker({
1845
+ url: gitlabUrl,
1846
+ gitlabAuthToken: options?.gitlabAuthToken
1847
+ });
1732
1848
  const results = await Promise.allSettled([
1733
1849
  (async () => {
1734
1850
  const res = await api2.Branches.show(projectPath, ref);
@@ -1769,8 +1885,8 @@ async function getGitlabReferenceData({ ref, gitlabUrl }, options) {
1769
1885
  }
1770
1886
  function parseGitlabOwnerAndRepo(gitlabUrl) {
1771
1887
  gitlabUrl = removeTrailingSlash2(gitlabUrl);
1772
- const parsingResult = parseScmURL(gitlabUrl);
1773
- if (!parsingResult || parsingResult.hostname !== "gitlab.com") {
1888
+ const parsingResult = parseScmURL(gitlabUrl, "GitLab" /* GitLab */);
1889
+ if (!parsingResult || !parsingResult.repoName) {
1774
1890
  throw new InvalidUrlPatternError(`invalid gitlab repo Url ${gitlabUrl}`);
1775
1891
  }
1776
1892
  const { organization, repoName, projectPath } = parsingResult;
@@ -1778,7 +1894,10 @@ function parseGitlabOwnerAndRepo(gitlabUrl) {
1778
1894
  }
1779
1895
  async function getGitlabBlameRanges({ ref, gitlabUrl, path: path9 }, options) {
1780
1896
  const { projectPath } = parseGitlabOwnerAndRepo(gitlabUrl);
1781
- const api2 = getGitBeaker({ gitlabAuthToken: options?.gitlabAuthToken });
1897
+ const api2 = getGitBeaker({
1898
+ url: gitlabUrl,
1899
+ gitlabAuthToken: options?.gitlabAuthToken
1900
+ });
1782
1901
  const resp = await api2.RepositoryFiles.allFileBlames(projectPath, path9, ref);
1783
1902
  let lineNumber = 1;
1784
1903
  return resp.filter((range) => range.lines).map((range) => {
@@ -1801,6 +1920,24 @@ var GitlabAuthResultZ = z4.object({
1801
1920
  token_type: z4.string(),
1802
1921
  refresh_token: z4.string()
1803
1922
  });
1923
+ function initGitlabFetchMock() {
1924
+ const globalFetch = global.fetch;
1925
+ function myFetch(input, init) {
1926
+ const stack = new Error().stack;
1927
+ const parts = stack?.split("at ");
1928
+ if (parts?.length && parts?.length >= 3 && parts[2]?.startsWith("defaultRequestHandler (") && parts[2]?.includes("/@gitbeaker/rest/dist/index.js") && (/^https?:\/\/[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}\//i.test(
1929
+ input?.url
1930
+ ) || "GITLAB_INTERNAL_DEV_HOST" in process.env && process.env["GITLAB_INTERNAL_DEV_HOST"] && input?.url?.startsWith(process.env["GITLAB_INTERNAL_DEV_HOST"]))) {
1931
+ const dispatcher = new ProxyAgent(
1932
+ process.env["GIT_PROXY_HOST"] || "http://tinyproxy:8888"
1933
+ );
1934
+ return globalFetch(input, { dispatcher });
1935
+ }
1936
+ return globalFetch(input, init);
1937
+ }
1938
+ global.fetch = myFetch;
1939
+ }
1940
+ initGitlabFetchMock();
1804
1941
 
1805
1942
  // src/features/analysis/scm/scmSubmit/index.ts
1806
1943
  import fs from "node:fs/promises";
@@ -1904,7 +2041,7 @@ function getCloudScmLibTypeFromUrl(url) {
1904
2041
  return void 0;
1905
2042
  }
1906
2043
  const urlObject = new URL(url);
1907
- const hostname = urlObject.hostname;
2044
+ const hostname = urlObject.hostname.toLowerCase();
1908
2045
  if (hostname === "gitlab.com") {
1909
2046
  return "GITLAB" /* GITLAB */;
1910
2047
  }
@@ -1952,7 +2089,7 @@ function getScmConfig({
1952
2089
  //if we the user does an ADO oauth flow then the token is saved for dev.azure.com but
1953
2090
  //sometimes the user uses the url dev.azure.com and sometimes the url visualstudio.com
1954
2091
  //so we need to check both
1955
- (urlObject.hostname === configUrl.hostname || urlObject.hostname.endsWith(".visualstudio.com") && configUrl.hostname === "dev.azure.com") && urlObject.protocol === configUrl.protocol && urlObject.port === configUrl.port
2092
+ (urlObject.hostname.toLowerCase() === configUrl.hostname.toLowerCase() || urlObject.hostname.toLowerCase().endsWith(".visualstudio.com") && configUrl.hostname.toLowerCase() === "dev.azure.com") && urlObject.protocol === configUrl.protocol && urlObject.port === configUrl.port
1956
2093
  );
1957
2094
  });
1958
2095
  const scmOrgConfig = filteredScmConfigs.find((scm) => scm.orgId && scm.token);
@@ -2285,6 +2422,15 @@ var AdoSCMLib = class extends SCMLib {
2285
2422
  getPr() {
2286
2423
  throw new Error("Method not implemented.");
2287
2424
  }
2425
+ postGeneralPrComment() {
2426
+ throw new Error("Method not implemented.");
2427
+ }
2428
+ getGeneralPrComments() {
2429
+ throw new Error("Method not implemented.");
2430
+ }
2431
+ deleteGeneralPrComment() {
2432
+ throw new Error("Method not implemented.");
2433
+ }
2288
2434
  };
2289
2435
  var GitlabSCMLib = class extends SCMLib {
2290
2436
  async createSubmitRequest(targetBranchName, sourceBranchName, title, body) {
@@ -2331,7 +2477,7 @@ var GitlabSCMLib = class extends SCMLib {
2331
2477
  console.error("no access token");
2332
2478
  throw new Error("no access token");
2333
2479
  }
2334
- return getGitlabRepoList(this.accessToken);
2480
+ return getGitlabRepoList(this.url, this.accessToken);
2335
2481
  }
2336
2482
  async getBranchList() {
2337
2483
  if (!this.accessToken || !this.url) {
@@ -2394,7 +2540,7 @@ var GitlabSCMLib = class extends SCMLib {
2394
2540
  console.error("no access token");
2395
2541
  throw new Error("no access token");
2396
2542
  }
2397
- return getGitlabUsername(this.accessToken);
2543
+ return getGitlabUsername(this.url, this.accessToken);
2398
2544
  }
2399
2545
  async getSubmitRequestStatus(scmSubmitRequestId) {
2400
2546
  if (!this.accessToken || !this.url) {
@@ -2425,6 +2571,7 @@ var GitlabSCMLib = class extends SCMLib {
2425
2571
  return await getGitlabBlameRanges(
2426
2572
  { ref, path: path9, gitlabUrl: this.url },
2427
2573
  {
2574
+ url: this.url,
2428
2575
  gitlabAuthToken: this.accessToken
2429
2576
  }
2430
2577
  );
@@ -2437,6 +2584,7 @@ var GitlabSCMLib = class extends SCMLib {
2437
2584
  return await getGitlabReferenceData(
2438
2585
  { ref, gitlabUrl: this.url },
2439
2586
  {
2587
+ url: this.url,
2440
2588
  gitlabAuthToken: this.accessToken
2441
2589
  }
2442
2590
  );
@@ -2447,6 +2595,7 @@ var GitlabSCMLib = class extends SCMLib {
2447
2595
  throw new Error("no url");
2448
2596
  }
2449
2597
  return await getGitlabRepoDefaultBranch(this.url, {
2598
+ url: this.url,
2450
2599
  gitlabAuthToken: this.accessToken
2451
2600
  });
2452
2601
  }
@@ -2459,6 +2608,15 @@ var GitlabSCMLib = class extends SCMLib {
2459
2608
  getPr() {
2460
2609
  throw new Error("Method not implemented.");
2461
2610
  }
2611
+ postGeneralPrComment() {
2612
+ throw new Error("Method not implemented.");
2613
+ }
2614
+ getGeneralPrComments() {
2615
+ throw new Error("Method not implemented.");
2616
+ }
2617
+ deleteGeneralPrComment() {
2618
+ throw new Error("Method not implemented.");
2619
+ }
2462
2620
  };
2463
2621
  var GithubSCMLib = class extends SCMLib {
2464
2622
  // we don't always need a url, what's important is that we have an access token
@@ -2727,6 +2885,48 @@ var GithubSCMLib = class extends SCMLib {
2727
2885
  pull_number: prNumber
2728
2886
  });
2729
2887
  }
2888
+ async postGeneralPrComment(params, auth) {
2889
+ const { prNumber, body } = params;
2890
+ if (!this.url) {
2891
+ console.error("no url");
2892
+ throw new Error("no url");
2893
+ }
2894
+ const oktoKit = auth ? new Octokit2({ auth: auth.authToken }) : this.oktokit;
2895
+ const { owner, repo } = parseGithubOwnerAndRepo(this.url);
2896
+ return await postGeneralPrComment(oktoKit, {
2897
+ issue_number: prNumber,
2898
+ owner,
2899
+ repo,
2900
+ body
2901
+ });
2902
+ }
2903
+ async getGeneralPrComments(params, auth) {
2904
+ const { prNumber } = params;
2905
+ if (!this.url) {
2906
+ console.error("no url");
2907
+ throw new Error("no url");
2908
+ }
2909
+ const oktoKit = auth ? new Octokit2({ auth: auth.authToken }) : this.oktokit;
2910
+ const { owner, repo } = parseGithubOwnerAndRepo(this.url);
2911
+ return await getGeneralPrComments(oktoKit, {
2912
+ issue_number: prNumber,
2913
+ owner,
2914
+ repo
2915
+ });
2916
+ }
2917
+ async deleteGeneralPrComment({ commentId }, auth) {
2918
+ if (!this.url) {
2919
+ console.error("no url");
2920
+ throw new Error("no url");
2921
+ }
2922
+ const oktoKit = auth ? new Octokit2({ auth: auth.authToken }) : this.oktokit;
2923
+ const { owner, repo } = parseGithubOwnerAndRepo(this.url);
2924
+ return deleteGeneralPrComment(oktoKit, {
2925
+ owner,
2926
+ repo,
2927
+ comment_id: commentId
2928
+ });
2929
+ }
2730
2930
  };
2731
2931
  var StubSCMLib = class extends SCMLib {
2732
2932
  async createSubmitRequest(_targetBranchName, _sourceBranchName, _title, _body) {
@@ -2813,6 +3013,15 @@ var StubSCMLib = class extends SCMLib {
2813
3013
  console.error("getPr() not implemented");
2814
3014
  throw new Error("getPr() not implemented");
2815
3015
  }
3016
+ postGeneralPrComment() {
3017
+ throw new Error("Method not implemented.");
3018
+ }
3019
+ getGeneralPrComments() {
3020
+ throw new Error("Method not implemented.");
3021
+ }
3022
+ deleteGeneralPrComment() {
3023
+ throw new Error("Method not implemented.");
3024
+ }
2816
3025
  };
2817
3026
 
2818
3027
  // src/features/analysis/scm/ado.ts
@@ -3071,7 +3280,9 @@ function getAdoDownloadUrl({
3071
3280
  branch
3072
3281
  }) {
3073
3282
  const { owner, repo, projectName } = parseAdoOwnerAndRepo(repoUrl);
3074
- return `https://dev.azure.com/${owner}/${projectName}/_apis/git/repositories/${repo}/items/items?path=/&versionDescriptor[versionOptions]=0&versionDescriptor[versionType]=commit&versionDescriptor[version]=${branch}&resolveLfs=true&$format=zip&api-version=5.0&download=true`;
3283
+ const url = new URL(repoUrl);
3284
+ const origin = url.origin.toLowerCase().endsWith(".visualstudio.com") ? "https://dev.azure.com" : url.origin.toLowerCase();
3285
+ return `${origin}/${owner}/${projectName}/_apis/git/repositories/${repo}/items/items?path=/&versionDescriptor[versionOptions]=0&versionDescriptor[versionType]=commit&versionDescriptor[version]=${branch}&resolveLfs=true&$format=zip&api-version=5.0&download=true`;
3075
3286
  }
3076
3287
  async function getAdoBranchList({
3077
3288
  accessToken,
@@ -3241,7 +3452,7 @@ async function getAdoReferenceData({
3241
3452
  }
3242
3453
  function parseAdoOwnerAndRepo(adoUrl) {
3243
3454
  adoUrl = removeTrailingSlash3(adoUrl);
3244
- const parsingResult = parseScmURL(adoUrl);
3455
+ const parsingResult = parseScmURL(adoUrl, "Ado" /* Ado */);
3245
3456
  if (!parsingResult || parsingResult.hostname !== "dev.azure.com" && !parsingResult.hostname.endsWith(".visualstudio.com")) {
3246
3457
  throw new InvalidUrlPatternError(`invalid ADO repo URL: ${adoUrl}`);
3247
3458
  }
@@ -3264,7 +3475,7 @@ var AdoAuthResultZ = z8.object({
3264
3475
  });
3265
3476
 
3266
3477
  // src/features/analysis/scm/constants.ts
3267
- var MOBB_ICON_IMG = "https://svgshare.com/i/12DK.svg";
3478
+ var MOBB_ICON_IMG = "https://app.mobb.ai/gh-action/Logo_Rounded_Icon.svg";
3268
3479
  var COMMIT_FIX_SVG = `https://app.mobb.ai/gh-action/commit-button.svg`;
3269
3480
 
3270
3481
  // src/features/analysis/scm/utils/get_issue_type.ts
@@ -3379,6 +3590,13 @@ function getCommitUrl(params) {
3379
3590
  })}/commit?${searchParams.toString()}`;
3380
3591
  }
3381
3592
 
3593
+ // src/features/analysis/utils/by_key.ts
3594
+ function keyBy(array, keyBy2) {
3595
+ return array.reduce((acc, item) => {
3596
+ return { ...acc, [item[keyBy2]]: item };
3597
+ }, {});
3598
+ }
3599
+
3382
3600
  // src/features/analysis/utils/calculate_ranges.ts
3383
3601
  function calculateRanges(integers) {
3384
3602
  if (integers.length === 0) {
@@ -3406,7 +3624,10 @@ function calculateRanges(integers) {
3406
3624
 
3407
3625
  // src/features/analysis/handle_finished_analysis.ts
3408
3626
  var debug4 = Debug4("mobbdev:handle-finished-analysis");
3627
+ var contactUsMarkdown = `For specific requests [contact us](https://mobb.ai/contact) and we'll do the most to answer your need quickly.`;
3409
3628
  var commitFixButton = (commitUrl) => `<a href="${commitUrl}"><img src=${COMMIT_FIX_SVG}></a>`;
3629
+ var MobbIconMarkdown = `![image](${MOBB_ICON_IMG})`;
3630
+ var noVulnerabilitiesFoundTitle = `# ${MobbIconMarkdown} No security issues were found \u2705`;
3410
3631
  function scannerToFriendlyString(scanner) {
3411
3632
  switch (scanner) {
3412
3633
  case "checkmarx":
@@ -3419,7 +3640,7 @@ function scannerToFriendlyString(scanner) {
3419
3640
  return "Snyk";
3420
3641
  }
3421
3642
  }
3422
- async function getFixesFromDiff(params) {
3643
+ async function getRelevantVulenrabilitiesFromDiff(params) {
3423
3644
  const { gqlClient, diff, vulnerabilityReportId } = params;
3424
3645
  const parsedDiff = parseDiff(diff);
3425
3646
  const fileHunks = parsedDiff.map((file) => {
@@ -3442,13 +3663,45 @@ async function getFixesFromDiff(params) {
3442
3663
  vulnerabilityReportId
3443
3664
  });
3444
3665
  }
3666
+ async function getFixesData(params) {
3667
+ const { gqlClient, fixesId } = params;
3668
+ const { fixes } = await gqlClient.getFixes(fixesId);
3669
+ return keyBy(fixes, "id");
3670
+ }
3671
+ function buildAnalysisSummaryComment(params) {
3672
+ const { prVulenrabilities: fixesFromDiff, fixesById } = params;
3673
+ const { vulnerabilityReportIssueCodeNodes, fixablePrVuls } = fixesFromDiff;
3674
+ const title = `# ${MobbIconMarkdown} ${fixablePrVuls} ${fixablePrVuls === 1 ? "fix is" : "fixes are"} ready to be committed`;
3675
+ const summary = Object.entries(
3676
+ // count every issue type
3677
+ vulnerabilityReportIssueCodeNodes.reduce(
3678
+ (result, vulnerabilityReportIssueCodeNode) => {
3679
+ const { vulnerabilityReportIssue } = vulnerabilityReportIssueCodeNode;
3680
+ const fix = fixesById[vulnerabilityReportIssue.fixId];
3681
+ if (!fix) {
3682
+ throw new Error(`fix ${vulnerabilityReportIssue.fixId} not found`);
3683
+ }
3684
+ const issueType = getIssueType(fix.issueType);
3685
+ const vulnerabilityReportIssueCount = (result[issueType] || 0) + 1;
3686
+ return {
3687
+ ...result,
3688
+ [issueType]: vulnerabilityReportIssueCount
3689
+ };
3690
+ },
3691
+ {}
3692
+ )
3693
+ ).map(([issueType, issueTypeCount]) => `**${issueType}** - ${issueTypeCount}`);
3694
+ return `${title}
3695
+ ${summary.join("\n")}`;
3696
+ }
3445
3697
  async function handleFinishedAnalysis({
3446
3698
  analysisId,
3447
3699
  scm: _scm,
3448
3700
  gqlClient,
3449
- githubActionOctokit,
3701
+ githubActionToken,
3450
3702
  scanner
3451
3703
  }) {
3704
+ const githubActionOctokit = new Octokit3({ auth: githubActionToken });
3452
3705
  if (_scm instanceof GithubSCMLib === false) {
3453
3706
  return;
3454
3707
  }
@@ -3462,17 +3715,59 @@ async function handleFinishedAnalysis({
3462
3715
  } = getAnalysis.analysis;
3463
3716
  const { commitSha, pullRequest } = getAnalysis.analysis.repo;
3464
3717
  const diff = await scm.getPrDiff({ pull_number: pullRequest });
3465
- const { vulnerabilityReportIssueCodeNodes } = await getFixesFromDiff({
3718
+ const prVulenrabilities = await getRelevantVulenrabilitiesFromDiff({
3466
3719
  diff,
3467
3720
  gqlClient,
3468
3721
  vulnerabilityReportId: getAnalysis.analysis.vulnerabilityReportId
3469
3722
  });
3470
- const comments = await scm.getPrComments(
3471
- { pull_number: pullRequest },
3472
- githubActionOctokit
3723
+ const { vulnerabilityReportIssueCodeNodes } = prVulenrabilities;
3724
+ const fixesId = vulnerabilityReportIssueCodeNodes.map(
3725
+ ({ vulnerabilityReportIssue: { fixId } }) => fixId
3473
3726
  );
3474
- await Promise.all(
3475
- comments.data.filter((comment) => {
3727
+ const fixesById = await getFixesData({ fixesId, gqlClient });
3728
+ const [comments, generalPrComments] = await Promise.all([
3729
+ scm.getPrComments({ pull_number: pullRequest }, githubActionOctokit),
3730
+ scm.getGeneralPrComments(
3731
+ { prNumber: pullRequest },
3732
+ { authToken: githubActionToken }
3733
+ )
3734
+ ]);
3735
+ async function postAnalysisSummary() {
3736
+ if (Object.values(fixesById).length === 0) {
3737
+ return;
3738
+ }
3739
+ const analysisSummaryComment = buildAnalysisSummaryComment({
3740
+ fixesById,
3741
+ prVulenrabilities
3742
+ });
3743
+ await scm.postGeneralPrComment(
3744
+ {
3745
+ body: analysisSummaryComment,
3746
+ prNumber: pullRequest
3747
+ },
3748
+ { authToken: githubActionToken }
3749
+ );
3750
+ }
3751
+ function deleteAllPreviousGeneralPrComments() {
3752
+ return generalPrComments.data.filter((comment) => {
3753
+ if (!comment.body) {
3754
+ return false;
3755
+ }
3756
+ return comment.body.includes(MOBB_ICON_IMG);
3757
+ }).map((comment) => {
3758
+ try {
3759
+ return scm.deleteGeneralPrComment(
3760
+ { commentId: comment.id },
3761
+ { authToken: githubActionToken }
3762
+ );
3763
+ } catch (e) {
3764
+ debug4("delete comment failed %s", e);
3765
+ return Promise.resolve();
3766
+ }
3767
+ });
3768
+ }
3769
+ function deleteAllPreviousComments() {
3770
+ return comments.data.filter((comment) => {
3476
3771
  return comment.body.includes(MOBB_ICON_IMG);
3477
3772
  }).map((comment) => {
3478
3773
  try {
@@ -3484,70 +3779,154 @@ async function handleFinishedAnalysis({
3484
3779
  debug4("delete comment failed %s", e);
3485
3780
  return Promise.resolve();
3486
3781
  }
3487
- })
3488
- );
3489
- return Promise.all(
3490
- vulnerabilityReportIssueCodeNodes.map(
3491
- async (vulnerabilityReportIssueCodeNodes2) => {
3492
- const { path: path9, startLine, vulnerabilityReportIssue } = vulnerabilityReportIssueCodeNodes2;
3493
- const { fixId } = vulnerabilityReportIssue;
3494
- const { fix_by_pk } = await gqlClient.getFix(fixId);
3495
- const {
3496
- patchAndQuestions: { patch }
3497
- } = fix_by_pk;
3498
- const commentRes = await scm.postPrComment(
3499
- {
3500
- body: "empty",
3501
- pull_number: pullRequest,
3502
- commit_id: commitSha,
3503
- path: path9,
3504
- line: startLine
3505
- },
3506
- githubActionOctokit
3507
- );
3508
- const commentId = commentRes.data.id;
3509
- const commitUrl = getCommitUrl({
3510
- appBaseUrl: WEB_APP_URL,
3511
- fixId: fix_by_pk.id,
3512
- projectId,
3513
- analysisId,
3514
- organizationId,
3515
- redirectUrl: commentRes.data.html_url,
3516
- commentId
3517
- });
3518
- const fixUrl = getFixUrlWithRedirect({
3519
- appBaseUrl: WEB_APP_URL,
3520
- fixId: fix_by_pk.id,
3521
- projectId,
3522
- analysisId,
3523
- organizationId,
3524
- redirectUrl: commentRes.data.html_url,
3525
- commentId
3526
- });
3527
- const scanerString = scannerToFriendlyString(scanner);
3528
- const issueType = getIssueType(fix_by_pk.issueType);
3529
- const title = `# ![image](${MOBB_ICON_IMG}) ${issueType} fix is ready`;
3530
- const subTitle = `### Apply the following code change to fix ${issueType} issue detected by ${scanerString}:`;
3531
- const diff2 = `\`\`\`diff
3782
+ });
3783
+ }
3784
+ await Promise.all([
3785
+ ...deleteAllPreviousComments(),
3786
+ ...deleteAllPreviousGeneralPrComments()
3787
+ ]);
3788
+ async function postFixComment(vulnerabilityReportIssueCodeNode) {
3789
+ const {
3790
+ path: path9,
3791
+ startLine,
3792
+ vulnerabilityReportIssue: { fixId }
3793
+ } = vulnerabilityReportIssueCodeNode;
3794
+ const fix = fixesById[fixId];
3795
+ if (!fix) {
3796
+ throw new Error(`fix ${fixId} not found`);
3797
+ }
3798
+ const {
3799
+ patchAndQuestions: { patch }
3800
+ } = fix;
3801
+ const commentRes = await scm.postPrComment(
3802
+ {
3803
+ body: "empty",
3804
+ pull_number: pullRequest,
3805
+ commit_id: commitSha,
3806
+ path: path9,
3807
+ line: startLine
3808
+ },
3809
+ githubActionOctokit
3810
+ );
3811
+ const commentId = commentRes.data.id;
3812
+ const commitUrl = getCommitUrl({
3813
+ appBaseUrl: WEB_APP_URL,
3814
+ fixId,
3815
+ projectId,
3816
+ analysisId,
3817
+ organizationId,
3818
+ redirectUrl: commentRes.data.html_url,
3819
+ commentId
3820
+ });
3821
+ const fixUrl = getFixUrlWithRedirect({
3822
+ appBaseUrl: WEB_APP_URL,
3823
+ fixId,
3824
+ projectId,
3825
+ analysisId,
3826
+ organizationId,
3827
+ redirectUrl: commentRes.data.html_url,
3828
+ commentId
3829
+ });
3830
+ const scanerString = scannerToFriendlyString(scanner);
3831
+ const issueType = getIssueType(fix.issueType);
3832
+ const title = `# ${MobbIconMarkdown} ${issueType} fix is ready`;
3833
+ const subTitle = `### Apply the following code change to fix ${issueType} issue detected by **${scanerString}**:`;
3834
+ const diff2 = `\`\`\`diff
3532
3835
  ${patch}
3533
3836
  \`\`\``;
3534
- const fixPageLink = `[Learn more and fine tune the fix](${fixUrl})`;
3535
- await scm.updatePrComment(
3536
- {
3537
- body: `${title}
3837
+ const fixPageLink = `[Learn more and fine tune the fix](${fixUrl})`;
3838
+ await scm.updatePrComment(
3839
+ {
3840
+ body: `${title}
3538
3841
  ${subTitle}
3539
3842
  ${diff2}
3540
3843
  ${commitFixButton(
3541
- commitUrl
3542
- )}
3844
+ commitUrl
3845
+ )}
3543
3846
  ${fixPageLink}`,
3544
- comment_id: commentId
3545
- },
3546
- githubActionOctokit
3547
- );
3548
- }
3549
- )
3550
- );
3847
+ comment_id: commentId
3848
+ },
3849
+ githubActionOctokit
3850
+ );
3851
+ }
3852
+ async function postAnalysisInsightComment() {
3853
+ const scanerString = scannerToFriendlyString(scanner);
3854
+ const {
3855
+ totalPrVulnerabilities,
3856
+ vulnerabilitiesOutsidePr,
3857
+ fixablePrVuls,
3858
+ nonFixablePrVuls
3859
+ } = prVulenrabilities;
3860
+ debug4({
3861
+ fixablePrVuls,
3862
+ nonFixablePrVuls,
3863
+ vulnerabilitiesOutsidePr,
3864
+ totalPrVulnerabilities
3865
+ });
3866
+ if (totalPrVulnerabilities === 0 && vulnerabilitiesOutsidePr === 0) {
3867
+ const body = `Awesome! No vulnerabilities were found by **${scanerString}**`;
3868
+ const noVulsFoundComment = `${noVulnerabilitiesFoundTitle}
3869
+ ${body}`;
3870
+ await scm.postGeneralPrComment(
3871
+ {
3872
+ body: noVulsFoundComment,
3873
+ prNumber: pullRequest
3874
+ },
3875
+ { authToken: githubActionToken }
3876
+ );
3877
+ return;
3878
+ }
3879
+ if (totalPrVulnerabilities === 0 && vulnerabilitiesOutsidePr > 0) {
3880
+ const body = `Awesome! No vulnerabilities were found by **${scanerString}** in the changes made as part of this PR.`;
3881
+ const body2 = `Please notice there are issues in this repo that are unrelated to this PR.`;
3882
+ const noVulsFoundComment = `${noVulnerabilitiesFoundTitle}
3883
+ ${body}
3884
+ ${body2}`;
3885
+ await scm.postGeneralPrComment(
3886
+ {
3887
+ body: noVulsFoundComment,
3888
+ prNumber: pullRequest
3889
+ },
3890
+ { authToken: githubActionToken }
3891
+ );
3892
+ return;
3893
+ }
3894
+ if (fixablePrVuls === 0 && nonFixablePrVuls > 0) {
3895
+ const title = `# ${MobbIconMarkdown} We couldn't fix the issues detected by **${scanerString}**`;
3896
+ const body = `Mobb Fixer gets better and better every day, but unfortunately your current issues aren't supported yet.`;
3897
+ const noFixableVulsComment = `${title}
3898
+ ${body}
3899
+ ${contactUsMarkdown}`;
3900
+ await scm.postGeneralPrComment(
3901
+ {
3902
+ body: noFixableVulsComment,
3903
+ prNumber: pullRequest
3904
+ },
3905
+ { authToken: githubActionToken }
3906
+ );
3907
+ return;
3908
+ }
3909
+ if (fixablePrVuls < nonFixablePrVuls && fixablePrVuls > 0) {
3910
+ const title = `# ${MobbIconMarkdown} We couldn't fix some of the issues detected by **${scanerString}**`;
3911
+ const body = "Mobb Fixer gets better and better every day, but unfortunately your current issues aren't supported yet.";
3912
+ const fixableVulsComment = `${title}
3913
+ ${body}
3914
+ ${contactUsMarkdown}`;
3915
+ await scm.postGeneralPrComment(
3916
+ {
3917
+ body: fixableVulsComment,
3918
+ prNumber: pullRequest
3919
+ },
3920
+ { authToken: githubActionToken }
3921
+ );
3922
+ return;
3923
+ }
3924
+ }
3925
+ await Promise.all([
3926
+ ...prVulenrabilities.vulnerabilityReportIssueCodeNodes.map(postFixComment),
3927
+ postAnalysisInsightComment(),
3928
+ postAnalysisSummary()
3929
+ ]);
3551
3930
  }
3552
3931
 
3553
3932
  // src/features/analysis/pack.ts
@@ -4162,7 +4541,7 @@ async function _scan(params, { skipPrompts = false } = {}) {
4162
4541
  analysisId,
4163
4542
  gqlClient,
4164
4543
  scm,
4165
- githubActionOctokit: new Octokit3({ auth: githubActionToken }),
4544
+ githubActionToken: z10.string().parse(githubActionToken),
4166
4545
  scanner: z10.nativeEnum(SCANNERS).parse(scanner)
4167
4546
  })
4168
4547
  );
@@ -4613,7 +4992,7 @@ Example:
4613
4992
  }
4614
4993
  var UrlZ = z11.string({
4615
4994
  invalid_type_error: "is not a valid GitHub / GitLab / ADO URL"
4616
- }).refine((data) => !!parseScmURL(data), {
4995
+ }).refine((data) => !!sanityRepoURL(data), {
4617
4996
  message: "is not a valid GitHub / GitLab / ADO URL"
4618
4997
  });
4619
4998
  function validateRepoUrl(args) {
@@ -4778,10 +5157,10 @@ function validateAddScmTokenOptions(argv) {
4778
5157
  );
4779
5158
  }
4780
5159
  const urlObj = new URL(argv.url);
4781
- if (urlObj.hostname === "github.com" && !argv.username) {
5160
+ if (urlObj.hostname.toLowerCase() === "github.com" && !argv.username) {
4782
5161
  throw new CliError("\nError: --username flag is required for GitHub");
4783
5162
  }
4784
- if ((urlObj.hostname === "dev.azure.com" || urlObj.hostname.endsWith(".visualstudio.com")) && !argv.organization) {
5163
+ if ((urlObj.hostname.toLowerCase() === "dev.azure.com" || urlObj.hostname.toLowerCase().endsWith(".visualstudio.com")) && !argv.organization) {
4785
5164
  throw new CliError(
4786
5165
  "\nError: --organization flag is required for Azure DevOps"
4787
5166
  );
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mobbdev",
3
- "version": "0.0.84",
3
+ "version": "0.0.86",
4
4
  "description": "Automated secure code remediation tool",
5
5
  "repository": "https://github.com/mobb-dev/bugsy",
6
6
  "main": "dist/index.js",
@@ -58,6 +58,7 @@
58
58
  "supports-color": "9.4.0",
59
59
  "tar": "6.2.0",
60
60
  "tmp": "0.2.1",
61
+ "undici": "6.7.0",
61
62
  "uuid": "9.0.1",
62
63
  "ws": "8.10.0",
63
64
  "yargs": "17.7.2",